<?php
/***************************************************************************
 * 
 * Copyright (c) 2010 , Inc. All Rights Reserved
 * $Id$:CSRFFilter.php,2010/06/22 10:39:20 
 * 
 **************************************************************************/
 
 
 
/**
 * @file CSRFFilter.php
 * @author huqingping
 * @date 2010/06/22 10:39:20
 * @version 1.0 
 * @brief 
 *  
 **/

final class CSRFFilter implements IFilter
{
	const TOKEN_EXPIRES = 10;
	const TOKEN_PRE = 'csrftk_';

	function execute(WebApp $app)
	{
		if ($app->request->method !== 'POST') {
			//继续往下执行，不进行csrf处理
			return true;
		}
		$url = parse_url($app->request->url);
		$arr = explode('/',trim($url['path'],'/'));
		$last = array_pop($arr);
		if (!$last || strncmp($last,'_',1)!==0) {
			//不是提交数据，就不管了
			return true;
		}
		//jid为每个独立访客都具有的一个cookie
		$jid = $app->request->getCookie('jid');
		if ('/_posttoken' == $app->request->url) {
			//请求得到一个token
			if (!$jid || strlen($jid) !== 32) {
				//不是一个正常的md5值,非法提交
				throw new Exception('hapn.u_notfound');
			}
			$token = $this->genToken($app,$jid);
			$app->response->set('token',$token);
			$app->response->send();
			return false;
		} else {
			if ($this->checkPostToken($app,$jid)) {
				return true;
			}
			//非法提交
			throw new Exception('hapn.u_notfound');
		}
	}

	function genToken($app,$jid)
	{
		$user = array('jid'=>$jid);
		$now = $app->request->now;
		$refer = $app->request->getHeader('Referer');

		$user['now'] = $now;
		$user['refer'] = $refer;
		
		$token = md5(json_encode($user));
		//把token内容存在cache里.
		$c = Com::get('Cache');
		$c->set(self::TOKEN_PRE.$jid, $user, Conf::get('csrf.expires',self::TOKEN_EXPIRES));
		return $token;
	}

	function checkPostToken($app,$jid)
	{
		$token = $app->request->get('_posttoken');
		if (!$token) {
			Logger::warning('csrf: post request with no csrf token');
			return false;
		}
		$c = Com::get('Cache');
		$user = $c->get(self::TOKEN_PRE.$jid);
		if (!$user) {
			Logger::warning('csrf: post request with invalid csrf token %s',$token);
			return false;
		}
		if ($user['jid'] != $jid) {
			Logger::warning('csrf: post request with invalid uid csrf token %s',$token);
			return false;
		}
		$expires = Conf::get('csrf.expires',self::TOKEN_EXPIRES);
		if ($user['now'] < ($app->request->now-$expires)) {
			//每个token几秒之后就过期了
			Logger::warning('csrf: post request with expired csrf token %s',$token);
			return false;
		}
		$refer = $app->request->getHeader('Referer');
		if ($user['refer'] != $refer) {
			Logger::warning('csrf: post request with invalid refer csrf token %s',$token);
			return false;
		}
		return true;
	}
}






/* vim: set ts=4 sw=4 sts=4 tw=100 noet: */
